#include <stdlib.h>
#include <assert.h>
#include <time.h>

#include "GL/glut.h"
#include "Sprite.h"
#include "include.h"

Sprite::Sprite()
{
	spriteId = DEFAULT_SPRITE_TYPE;
	textureVertices = NULL;
	position = Vector2D(0,0);
	birthTime = clock();
	lifespan = 10;
	deathTime = birthTime + 10 * (float)CLOCKS_PER_SEC;
	startSize = Vector2D(1.0,1.0);
	boundingRadius = 1.0;
	endSize = Vector2D(10.0,10.0);
	sizeDelta = (endSize - startSize) / lifespan;
	this->textureManager = NULL;
}
Sprite::Sprite(Vector2D position, Vector2D size, float lifespan)
{
	spriteId = DEFAULT_SPRITE_TYPE;
	textureVertices = NULL;
	this->position = position;
	birthTime = clock();
	this->lifespan = lifespan;
	deathTime = birthTime + lifespan * (float)CLOCKS_PER_SEC;
	startSize = size;
	endSize = size;
	sizeDelta = Vector2D(0,0);
	this->textureManager = NULL;
	if(size.x > size.y)
		boundingRadius = size.x;
	else
		boundingRadius = size.y;
}
Sprite::Sprite(Vector2D position, Vector2D startSize, Vector2D endSize, float lifespan)
{
	spriteId = DEFAULT_SPRITE_TYPE;
	textureVertices = NULL;
	this->position = position;
	birthTime = clock();
	this->lifespan = lifespan;
	deathTime = birthTime + lifespan * (float)CLOCKS_PER_SEC;
	this->startSize = startSize;
	this->endSize = endSize;
	sizeDelta = (endSize - startSize) / lifespan;
	this->textureManager = NULL;
	if(startSize.x > startSize.y)
		boundingRadius = startSize.x;
	else
		boundingRadius = startSize.y;
}
Sprite::Sprite(Vector2D position, Vector2D size, float lifespan, TextureManager * textureManager, char * filename)
{
	spriteId = DEFAULT_SPRITE_TYPE;
	textureVertices = NULL;
	this->position = position;
	birthTime = clock();
	this->lifespan = lifespan;
	deathTime = birthTime + lifespan * (float)CLOCKS_PER_SEC;
	startSize = size;
	endSize = size;
	sizeDelta = Vector2D(0,0);
	if(size.x > size.y)
		boundingRadius = size.x;
	else
		boundingRadius = size.y;
	this->textureManager = textureManager;
	textureManager->LoadTexture(filename);
	textureIndex = textureManager->TextureIndex(filename);
}
Sprite::Sprite(Vector2D position, Vector2D startSize, Vector2D endSize, float lifespan, TextureManager * textureManager, char * filename)
{
	spriteId = DEFAULT_SPRITE_TYPE;
	textureVertices = NULL;
	this->position = position;
	birthTime = clock();
	this->lifespan = lifespan;
	deathTime = birthTime + lifespan * (float)CLOCKS_PER_SEC;
	this->startSize = startSize;
	this->endSize = endSize;
	if(startSize.x > startSize.y)
		boundingRadius = startSize.x;
	else
		boundingRadius = startSize.y;
		
	sizeDelta = (endSize - startSize) / lifespan;
	this->textureManager = textureManager;
	this->textureManager->LoadTexture(filename);
	textureIndex = this->textureManager->TextureIndex(filename);
}
Sprite::Sprite(Vector2D position, Vector2D size, float lifespan, TextureManager * textureManager, char * filename, int spriteId)
{
	this->spriteId = spriteId;
	textureVertices = NULL;
	this->position = position;
	birthTime = clock();
	this->lifespan = lifespan;
	deathTime = birthTime + lifespan * (float)CLOCKS_PER_SEC;
	startSize = size;
	endSize = size;
	sizeDelta = Vector2D(0,0);
	if(size.x > size.y)
		boundingRadius = size.x;
	else
		boundingRadius = size.y;
	
	this->textureManager = textureManager;
	textureManager->LoadTexture(filename);
	textureIndex = textureManager->TextureIndex(filename);
}
bool Sprite::IsDead()
{
	if( clock() > deathTime)
		return true;
	return false;
}
void Sprite::Draw()
{
	
	glBlendFunc(GL_ONE_MINUS_SRC_ALPHA,GL_SRC_ALPHA);
	float time = (float) clock();
	if(textureManager)
	{
		textureManager->EnableTexture(textureIndex);
		glColor4f(1,1,1,0.9);
		glEnable(GL_TEXTURE_2D);
		glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
		glAlphaFunc( GL_GREATER, 0.01 );
  		glEnable( GL_ALPHA_TEST );
  		glEnable(GL_BLEND); 
  		//glBlendFunc(GL_ONE, GL_ONE);
  		//glBlendFunc(GL_SRC_COLOR, GL_SRC_COLOR);//GL_DST_COLOR);
  		glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
  		
	}
  	
	if(lifespan < 0 || time < deathTime)
	{
		
		Vector2D size = startSize + sizeDelta * (time - birthTime)/(float)CLOCKS_PER_SEC;
		
		if(size.x > size.y)
			boundingRadius = size.x;
		else
			boundingRadius = size.y;
			
		Vector2D vertices[4] = {Vector2D(position.x - size.x * 0.5, position.y + size.y * 0.5),
								Vector2D(position.x + size.x * 0.5, position.y + size.y * 0.5),
								Vector2D(position.x + size.x * 0.5, position.y - size.y * 0.5),
								Vector2D(position.x - size.x * 0.5, position.y - size.y * 0.5)};
		Vector2D texVertices[4] = {Vector2D(0,1),Vector2D(1,1),Vector2D(1,0),Vector2D(0,0)};
		
		if(textureVertices)
		{
			texVertices[0] = textureVertices[0];
			texVertices[1] = textureVertices[1];
			texVertices[2] = textureVertices[2];
			texVertices[3] = textureVertices[3];
		}
			
		glBegin(GL_QUADS);
		for(int i = 0; i < 4; i++)
		{
			glTexCoord2f(texVertices[i].x, texVertices[i].y);
			glVertex2f(vertices[i].x, vertices[i].y);
		}
		glEnd();
	}
	glDisable(GL_BLEND); 
	glDisable( GL_ALPHA_TEST );
	glDisable(GL_TEXTURE_2D);
	SpriteDrawEntryPoint();
	
}
void Sprite::SpriteDrawEntryPoint()
{
}
void Sprite::Think(double elapsedTime)
{
}
void Sprite::ProjectPolygon(Vector2D axis, float * min, float * max, Vector2D * minVertex, Vector2D * maxVertex, float * minError, float * maxError)
{

	//make sure the axis points in the +x and +y directions
	float xDir = Vector2D(1,0).dot(axis);
	float yDir = Vector2D(0,1).dot(axis);
	if(abs(xDir)>abs(yDir))
	{
		if(xDir < 0)
			axis = -1.0 * axis;
	}
	else
	{
		if(yDir < 0)
			axis = -1.0 * axis;
	}
			
	float time = (float) clock();
	Vector2D size = startSize + sizeDelta * (time - birthTime)/(float)CLOCKS_PER_SEC;
	Vector2D vertices[4];
	vertices[0] = Vector2D(-2,2);//Vector2D(-0.5 * size.x, 0.5 * size.y);
	vertices[1] = Vector2D(2,2);//Vector2D(0.5 * size.x,  0.5 * size.y);
	vertices[2] = Vector2D(2,-2);//Vector2D(0.5 * size.x,  -0.5 * size.y);
	vertices[3] = Vector2D(-2,-2);//Vector2D(-0.5 * size.x, -0.5 * size.y);
	
	float dotProduct = axis.dot(vertices[0] + position);
	*min = dotProduct;
	*max = dotProduct;
	*minVertex = vertices[0];
	*maxVertex = vertices[0];
	int minCount = 1;
	int maxCount = 1;
	*minError = 0.0;
	*maxError = 0.0;
	int minErrorCount = 0;
	int maxErrorCount = 0;
	for(int i = 1; i < 4; i++)
	{
		dotProduct = axis.dot(vertices[i] + position);
		if(dotProduct < *min)
		{
			minCount = 1;
			minErrorCount = 0;
			*minError = 0.0;
			*min = dotProduct;
			*minVertex = vertices[i];
		}
		else if( dotProduct == *min)
		{
			*minError += vertices[i].dist(*minVertex);
			*minVertex = *minVertex + vertices[i];
			minCount++;
			minErrorCount++;
			
		}
		else if(dotProduct > *max)
		{
			maxCount = 1;
			maxErrorCount = 0;
			*maxError = 0.0;
			*max = dotProduct;
			*maxVertex = vertices[i];
		}
		else if(dotProduct == *max)
		{
			*maxError += vertices[i].dist(*maxVertex);
			*maxVertex = *maxVertex + vertices[i];
			maxCount++;
		}
	}
	if(minErrorCount > 0)
		*minError /= (float)minErrorCount;
	if(maxErrorCount > 0)
		*maxError /= (float)maxErrorCount;
	*minVertex = *minVertex / (float)minCount;
	*maxVertex = *maxVertex / (float)maxCount;
} 
Vector2D Sprite::GetVertex(int index)
{
	float time = (float) clock();
	Vector2D size = startSize + sizeDelta * (time - birthTime)/(float)CLOCKS_PER_SEC;
	
	int xSign = 1;
	int ySign = 1;
	if(index == 0 || index == 3)
		xSign = -1;
	if(index == 2 || index == 3)
		ySign = -1;
	return Vector2D(xSign * 0.5 * size.x, ySign * 0.5 * size.y);
}
Sprite::~Sprite()
{
	if(textureVertices)
		delete(textureVertices);
	textureVertices = NULL;
}
		